home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 42 / Amiga Format AFCD42 (Issue 126, Aug 1999).iso / -serious- / comms / other / slrn / slrn_src / src / slrnpull.c < prev    next >
C/C++ Source or Header  |  1999-05-14  |  52KB  |  2,529 lines

  1. /* -*- mode: C; mode: fold -*- */
  2. /* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
  3.  *
  4.  * This file is part of slrn.
  5.  *
  6.  * Slrn is free software; you can redistribute it and/or modify it
  7.  * under the terms of the GNU General Public License as published by the
  8.  * Free Software Foundation; either version 2, or (at your option) any
  9.  * later version.
  10.  * 
  11.  * Slrn is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * for more details.
  15.  * 
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with Slrn; see the file COPYING.  If not, write to the Free
  18.  * Software Foundation, 59 Temple Place - Suite 330, 
  19.  * Boston, MA  02111-1307, USA.
  20.  */
  21.  
  22.  
  23. #include "config.h"
  24.  
  25. #define SLRNPULL_CODE
  26. #include "slrnfeat.h"
  27.  
  28. /*{{{ System Includes */
  29.  
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <errno.h>
  33. #include <signal.h>
  34. #include <sys/types.h>
  35. #include <time.h>
  36.  
  37. #include <sys/stat.h>
  38.  
  39. #ifdef HAVE_STDLIB_H
  40. # include <stdlib.h>
  41. #endif
  42. #ifdef HAVE_FCNTL_H
  43. # include <fcntl.h>
  44. #endif
  45. #ifdef HAVE_UNISTD_H
  46. # include <unistd.h>
  47. #endif
  48.  
  49. #include <ctype.h>
  50.  
  51. #ifndef S_ISREG
  52. # define S_ISREG(mode)  (((mode) & (_S_IFMT)) == (_S_IFREG))
  53. #endif
  54.  
  55. #include <slang.h>
  56. #include "jdmacros.h"
  57. /*}}}*/
  58.  
  59. /*{{{ Local Includes */
  60.  
  61. #include "ttymsg.h"
  62. #include "util.h"
  63. #include "sltcp.h"
  64. #include "nntplib.h"
  65. #include "nntpcodes.h"
  66. #include "slrndir.h"
  67. #include "version.h"
  68.  
  69. #include "score.c"
  70. #include "xover.c"
  71.  
  72. #undef SLRN_HAS_MSGID_CACHE
  73. #define SLRN_HAS_MSGID_CACHE 1
  74.  
  75. #include "hash.c"
  76. /*}}}*/
  77.  
  78. /*{{{ slrnpull global variables and structures */
  79.  
  80. #ifndef SLRNPULL_ROOT_DIR
  81. # define SLRNPULL_ROOT_DIR    "/var/spool/news/slrn"
  82. #endif
  83.  
  84. #ifndef SLRNPULL_CONF
  85. # define SLRNPULL_CONF        "slrnpull.conf"
  86. #endif
  87.  
  88. #ifndef SLRNPULL_OUTGOING_DIR
  89. # define SLRNPULL_OUTGOING_DIR    "out.going"
  90. #endif
  91.  
  92. #if SLRNPULL_USE_SETGID_POSTS
  93. # define OUTGOING_DIR_MODE    (0777 | 03000)
  94. #else
  95. # define OUTGOING_DIR_MODE    (0777 | 01000)
  96. #endif
  97.  
  98. #ifndef SLRNPULL_SCORE_FILE
  99. # define SLRNPULL_SCORE_FILE    "score"
  100. #endif
  101.  
  102. #ifndef SLRNPULL_NEWS_DIR
  103. # define SLRNPULL_NEWS_DIR    "news"
  104. #endif
  105.  
  106. #ifndef SLRNPULL_LOGFILE
  107. # define SLRNPULL_LOGFILE    "log"
  108. #endif
  109.  
  110. #ifndef SLRNPULL_OUTGOING_BAD_DIR
  111. # define SLRNPULL_OUTGOING_BAD_DIR    "rejects"
  112. #endif
  113.  
  114. #ifndef SLRNPULL_OUTGOING_DIR_MODE
  115. # define SLRNPULL_OUTGOING_DIR_MODE    (0777 | 01000)
  116. #endif
  117.  
  118. static int Exit_Code;
  119. #define SLRN_EXIT_UNKNOWN        1
  120. #define SLRN_EXIT_BAD_USAGE        2
  121. #define SLRN_EXIT_CONNECTION_FAILED    3
  122. #define SLRN_EXIT_CONNECTION_LOST    4
  123. #define SLRN_EXIT_SIGNALED        5
  124. #define SLRN_EXIT_MALLOC_FAILED        10
  125.  
  126. #define SLRN_EXIT_FILEIO        20
  127.  
  128. char *SlrnPull_Dir = SLRNPULL_ROOT_DIR;
  129. char *SlrnPull_Spool_News_Dir;
  130. char *Group_Min_Max_File;           /* relative to group dir */
  131. char *Overview_File;           /* relative to group dir */
  132. char *Outgoing_Dir;
  133. char *Outgoing_Bad_Dir;
  134. char *New_Groups_File = "new.groups";
  135. char *New_Groups_Time_File = "new.groups-time";
  136. char *Data_Dir = "data";
  137. static char *Active_File = "active";
  138.  
  139. static int Stdout_Is_TTY;
  140. static char *Active_Groups_File;
  141. static time_t Start_Time;
  142.  
  143. #define CREATE_OVERVIEW 1
  144.  
  145.  
  146. static int handle_interrupts (void);
  147.  
  148. typedef struct _Active_Group_Type /*{{{*/
  149. {
  150.    unsigned int flags;
  151.    
  152.    /* Unfortunately, three different sets of article ranges are required.  
  153.     * Ideally, only one would be required but this does not seem to be 
  154.     * possible.  This is because the articles in the spool directory 
  155.     * created by slrnpull do not expire when the articles on the server
  156.     * expire.  In addition, slrnpull removes duplicate articles so that
  157.     * the articles present on the server may not actually be present in the 
  158.     * spool directory.  
  159.     * 
  160.     * The main problem is that it appears that some servers will reuse 
  161.     * article numbers from articles that have been cancelled.  The spool 
  162.     * directory created by slrnpull does not know about cancel messages,
  163.     * which means that the same article number can refer to two different
  164.     * articles.  The ultimate solution would be for slrnpull to use its own
  165.     * numbering scheme that is independent of the server's.  This would mean
  166.     * caching all message-ids and stripping Xref headers from the articles
  167.     * that are received from the server.  At first sight it would appear that
  168.     * new Xref headers would have to be generated for the .overview files but
  169.     * since slrnpull removes duplicates, this should not be necessary.  A
  170.     * major advantage of this approach is that one could merge multiple feeds.
  171.     * A rough estimate of the size of the message-id cache is 100 * 500 * 80,
  172.     * or 4,000,000 bytes assuming 100 newsgroups with 500 articles per group
  173.     * and a message id of 80 characters.  Of course that number would be
  174.     * smaller if Pine were eliminated.
  175.     */
  176.    unsigned int min, max;           /* range of articles that slrnpull has 
  177.                     already dealt with */
  178.    unsigned int active_min, active_max;/* article numbers that are in spool dir */
  179.    unsigned int server_min;           /* artcle numbers that server reports */
  180.    unsigned int server_max;
  181.    
  182.    
  183.    unsigned int max_to_get;           /* if non-zero, get only this many */
  184.    unsigned int expire_days;           /* if zero, no expiration */
  185. #define MAX_GROUP_NAME_LEN 80
  186.    char name [MAX_GROUP_NAME_LEN + 1];
  187.    char dirname [MAX_GROUP_NAME_LEN + 1];
  188.    struct _Active_Group_Type *next;
  189. }
  190.  
  191. /*}}}*/
  192. Active_Group_Type;
  193.  
  194. static char *Current_Newsgroup;
  195.  
  196. static Active_Group_Type *Active_Groups;
  197. static Active_Group_Type *Active_Groups_Tail;
  198.  
  199. /*}}}*/
  200.  
  201. static FILE *MLog_Fp;
  202. static FILE *ELog_Fp;
  203.  
  204. static void write_timestamp (FILE *fp) /*{{{*/
  205. {
  206.    struct tm *tms;
  207.    time_t tloc;
  208.    
  209.    time (&tloc);
  210.    tms = localtime (&tloc);
  211.    
  212.    fprintf (fp, "%02d/%02d/%04d %02d:%02d:%02d ",
  213.         tms->tm_mon + 1, tms->tm_mday, 1900 + tms->tm_year,
  214.         tms->tm_hour, tms->tm_min, tms->tm_sec);
  215.    
  216. }
  217.  
  218. /*}}}*/
  219.  
  220. static void write_log (FILE *fp, char *pre, char *buf)
  221. {
  222.    write_timestamp (fp);
  223.    if (pre != NULL) fputs (pre, fp);
  224.    fputs (buf, fp);
  225.    fputc ('\n', fp);
  226.    fflush (fp);
  227. }
  228.  
  229. static void va_log (FILE *fp, char *pre, char *fmt, va_list ap) /*{{{*/
  230. {
  231.    char buf[2048];   
  232.  
  233.    vsprintf (buf, fmt, ap);
  234.    
  235.    write_log (fp, pre, buf);
  236.    
  237.    if ((Stdout_Is_TTY == 0) || (fp == stdout) || (fp == stderr))
  238.      return;
  239.    if (fp == MLog_Fp) fp = stdout; else fp = stderr;
  240.  
  241.    write_log (fp, pre, buf);
  242. }
  243.  
  244. /*}}}*/
  245.  
  246. static void log_message (char *fmt, ...) /*{{{*/
  247. {
  248.    va_list ap;
  249.    
  250.    va_start (ap, fmt);
  251.    va_log (MLog_Fp, NULL, fmt, ap);
  252.    va_end (ap);
  253. }
  254.  
  255. /*}}}*/
  256.  
  257. static void log_error (char *fmt, ...) /*{{{*/
  258. {
  259.    va_list ap;
  260.    
  261.    va_start (ap, fmt);
  262.    va_log (ELog_Fp, "***", fmt, ap);
  263.    va_end (ap);
  264. }
  265.  
  266. /*}}}*/
  267.  
  268. static void va_log_error (char *fmt, va_list ap) /*{{{*/
  269. {
  270.    va_log (ELog_Fp, "***", fmt, ap);
  271. }
  272.  
  273. /*}}}*/
  274.  
  275. static void va_log_message (char *fmt, va_list ap) /*{{{*/
  276. {
  277.    va_log (MLog_Fp, NULL, fmt, ap);
  278. }
  279.  
  280. /*}}}*/
  281.  
  282. static Active_Group_Type *find_group_type (char *name) /*{{{*/
  283. {
  284.    Active_Group_Type *g;
  285.    
  286.    g = Active_Groups;
  287.    while (g != NULL)
  288.      {
  289.     if (!strcmp (name, g->name))
  290.       break;
  291.     
  292.     g = g->next;
  293.      }
  294.    
  295.    return g;
  296. }
  297.  
  298. /*}}}*/
  299.  
  300. static Active_Group_Type *add_group_type (char *name) /*{{{*/
  301. {
  302.    Active_Group_Type *g;
  303.    
  304.    g = (Active_Group_Type *) slrn_malloc (sizeof (Active_Group_Type), 1, 1);
  305.    
  306.    if (g == NULL)
  307.      return NULL;
  308.    
  309.    strncpy (g->name, name, MAX_GROUP_NAME_LEN);   /* null terminated 
  310.                            * by construction */
  311.    
  312.    if (Active_Groups_Tail != NULL)
  313.      Active_Groups_Tail->next = g;
  314.    else 
  315.      Active_Groups = g;
  316.    
  317.    Active_Groups_Tail = g;
  318.    return g;
  319. }
  320.  
  321. /*}}}*/
  322.  
  323. #if defined(__MINGW32__)
  324. # define MKDIR(x,y) mkdir(x)
  325. #else
  326. # define MKDIR(x,y) mkdir(x,y)
  327. #endif
  328.  
  329. static int do_mkdir (char *dir, int err) /*{{{*/
  330. {
  331.    if (0 == MKDIR (dir, 0777))
  332.      {
  333.     log_message ("Created dir %s.", dir);
  334.     return 0;
  335.      }
  336.    
  337.    if (errno == EEXIST)
  338.      return 0;
  339.     
  340.    if (err)
  341.      log_error ("Unable to create directory %s. (errno = %d)", dir, errno);
  342.  
  343.    return -1;
  344. }
  345.  
  346. /*}}}*/
  347.  
  348. static FILE *open_group_min_max_file (Ac